package cn.tedu.charging.order.service.impl;

import cn.tedu.charging.common.pojo.JsonResult;
import cn.tedu.charging.common.pojo.param.GunStatusUpdateParam;
import cn.tedu.charging.common.pojo.vo.StationInfoVO;
import cn.tedu.charging.common.pojo.vo.UserInfoVO;
import cn.tedu.charging.common.utils.JsonUtils;
import cn.tedu.charging.order.RabbitMQ.RabbitMQProducer;
import cn.tedu.charging.order.common.ChargingConstants;
import cn.tedu.charging.order.common.GunStatusConstants;
import cn.tedu.charging.order.common.MqttConstants;
import cn.tedu.charging.order.feign.DeviceClient;
import cn.tedu.charging.order.feign.UserClient;
import cn.tedu.charging.order.mqtt.MqttProducer;
import cn.tedu.charging.order.pojo.dto.ChargingDTO;
import cn.tedu.charging.order.pojo.param.OrderCreateParam;
import cn.tedu.charging.order.quartz.DeviceCheckJob;
import cn.tedu.charging.order.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.Random;

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
    /**
     *
     * 1. 生成订单号 （生产的逻辑）
     * 2. 获取 用户信息（车辆id） (微服务架构  订单服务调用 用户服务 服务之间通信)
     * 3. 获取 服务信息（场站信息和设备信息 充电站id,运营商id...） (微服务架构  订单服务调用 设备服务 服务之间通信)
     * 4. 修改充电枪的状态 为 使用中  (微服务架构  订单服务调用 设备服务 服务之间通信)
     * 5. 给设备发送开始充电指令 （物联网 订单服务 调用 充电桩设备 服务于设备之间通信）
     *
     * @param orderCreateParam
     * @return
     */

    @Override
    public String createOrder(OrderCreateParam orderCreateParam) {
        log.debug("创建订单:{}",orderCreateParam);
        // 生成订单号
        log.debug("创建订单-生成订单号");
        String orderNo = getOrderNo();
        log.debug("创建订单-生成订单号:{}",orderNo);
        //2. 获取用户信息
        Integer userId = orderCreateParam.getUserId();
        log.debug("创建订单-获取用户信息-入参:{}",userId);
        UserInfoVO userInfo = getUserInfoByOpenFeign(userId);
        log.debug("创建订单-获取用户信息-入参:{},出参:{}",userId,userInfo);
        //3. 获取场站信息
        Integer gunId = orderCreateParam.getGunId();
        log.debug("创建订单-获取场站信息-入参:{}",gunId);
        StationInfoVO stationInfoVO = getStationInfo(gunId);
        log.debug("创建订单-获取场站信息-入参:{},出参:{}",gunId,stationInfoVO);
        //4. 修改充电枪的状态 为 使用中
        log.debug("创建订单-修改充电枪状态为使用中-入参:{},{}",gunId, GunStatusConstants.GUN_STATUS_USING);
        Boolean result = upDateGunStatus(gunId, GunStatusConstants.GUN_STATUS_USING);
        log.debug("创建订单-修改充电枪状态为使用中-入参:{},{},出参:{}",gunId,GunStatusConstants.GUN_STATUS_USING,result);
        //5. 给设备发送开始充电指令（物联网 订单服务 调用 充电桩设备 服务于设备之间通信）
        startCharging(orderNo, orderCreateParam.getPileId(), orderCreateParam.getGunId());
        //6. 创建设备检查任务，用来检查设备无响应
        log.debug("创建订单-创建设备检查任务-入参:{}",orderNo);
        try {
            DeviceCheckJob deviceCheckJob = new DeviceCheckJob(orderNo);
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }
        log.debug("创建订单-创建设备检查任务成功-入参:{}",orderNo);
        log.debug("创建订单-给消息队列发送有生存时间的消息，实现" +
                "延迟消息，用来处理超时订单<<充电过程中的设备故障>>-入参:{}",orderNo);
        Boolean success = sendMessage(orderNo);
        log.debug("创建订单-给消息队列发送有生存时间的消息，实现" +
                "延迟消息，用来处理超时订单<<充电过程中的设备故障>>-入参:{},结果:{}",orderNo,success);
        return orderNo;
    }
    @Autowired
    private RabbitMQProducer rabbitMQProducer;

    private Boolean sendMessage(String orderNo) {
        rabbitMQProducer.sendMessage(orderNo);
        return true;
    }



    @Autowired
    private MqttProducer mqttProducer;

    private void startCharging(String orderNo, Integer pileId, Integer gunId) {
        String topic = MqttConstants.TOPIC_STATUS_CHARGING_PREFIX + pileId;
        ChargingDTO chargingDTO = new ChargingDTO();
        chargingDTO.setOrderNo(orderNo);
        chargingDTO.setPileId(pileId);
        chargingDTO.setGunId(gunId);
        chargingDTO.setMsg(ChargingConstants.START_CHARGING);
        log.debug("订单服务发送开始充电指令到设备Topic:{},消息:{}",topic,chargingDTO);
        String message = JsonUtils.toJson(chargingDTO);
        log.debug("订单服务发送开始充电指令到设备Topic:{},消息对象:{}，消息json:{}",topic, chargingDTO, message);
        Boolean sent = mqttProducer.sendMessage(topic, message);
        log.debug("订单服务发送开始充电指令到设备Topic:{},消息对象:{}，消息json:{},消息发送结果:{}",topic,chargingDTO, message,sent);
    }



    @Autowired
    private DeviceClient deviceClient;


    private Boolean upDateGunStatus(Integer gunId, Integer status) {
        GunStatusUpdateParam param = new GunStatusUpdateParam();
        param.setGunId(gunId);
        param.setStatus(1);
        JsonResult<Boolean> result = deviceClient.upDateGunStatus(param);
        return result.getData();
    }

    /**
     * 通过OpenFeign调用设备服务获取场站信息
     * @param gunId
     * @return
     */
    private StationInfoVO getStationInfo(Integer gunId) {
        JsonResult<StationInfoVO> stationInfo = deviceClient.getStationInfo(gunId);
        return stationInfo.getData();
    }


    @Autowired
    private UserClient userClient;

    /**
     * 通过OpenFeign调用用户服务获取用户信息
     * @param userId
     * @return
     */
    private UserInfoVO getUserInfoByOpenFeign(Integer userId) {
        JsonResult<UserInfoVO> userInfo = userClient.getUserInfo(userId);
        UserInfoVO data = userInfo.getData();
        return data;
    }


    @Autowired
    private RestTemplate restTemplate;


    private UserInfoVO getUserInfo(Integer userId) {
        String url = getUrl();
        log.debug("通过用户服务获取用户信息接口地址:{}",url);
        ParameterizedTypeReference<JsonResult<UserInfoVO>> repType = new ParameterizedTypeReference<JsonResult<UserInfoVO>>() {};
        ResponseEntity<JsonResult<UserInfoVO>> entity = restTemplate.exchange(url, HttpMethod.GET, null, repType, userId);
        JsonResult<UserInfoVO> body = entity.getBody();
        UserInfoVO data = body.getData();

        return data;
    }


    private String getUrl() {
        String url1 = "http://localhost:8080/user/info/{userId}";
        String url2 = "http://localhost:8081/user/info/{userId}";
        String url3 = "http://localhost:8082/user/info/{userId}";
        String[] urls = new String[]{url1,url2,url3};
        Random random = new Random();
        int index = random.nextInt(urls.length);
        return urls[index];
    }

    /**
     * 生成订单号
     * @return
     */

    private String getOrderNo() {
        //1. 订单号前缀
        String start = "100000";
        Random random = new Random();
        //2. 生成100000之内的随机数
        int r = random.nextInt(100000);
        //3. 时间戳
        long now = System.currentTimeMillis();
        return start + "_" + r + "_" + now;
    }
}
